package net.qiqb.spring;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import net.qiqb.core.domain.annotation.AggregatePersistence;
import net.qiqb.core.domain.annotation.AggregateRootLoader;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.ResolvableType;
import org.springframework.core.type.MethodMetadata;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Method;
import java.util.*;

public class DomainObjectLoaderProcessor implements BeanFactoryPostProcessor, SmartInitializingSingleton {


    private ConfigurableListableBeanFactory beanFactory;

    private final Map<String, String> aggregateRootLoaderMap = new HashMap<>();

    private final Map<String, String> aggregatePersistenceMap = new HashMap<>();


    private void registerAggregateRootLoader(String businessIdName, String aggregateRootName, String aggregateRootLoaderBeanName) {
        this.aggregateRootLoaderMap.put(aggregateRootName + ":" + businessIdName, aggregateRootLoaderBeanName);
    }

    private void registerAggregatePersistence(String businessName, String aggregatePersistenceBeanName) {
        this.aggregatePersistenceMap.put(businessName, aggregatePersistenceBeanName);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;

        for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
            final BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName);
            if (beanDefinitionName.equals("transportPersistence")) {
                System.out.println("TransportPersistence");
            }
            String implTypeClassName = beanDefinition.getBeanClassName();

            if (!ObjectUtils.isEmpty(implTypeClassName)) {
                final Class<Object> declaringClass = ClassUtil.loadClass(implTypeClassName);
                final ResolvableType resolvableType = ResolvableType.forClass(declaringClass);
                final Class<?> aggretateClass = getResolvableType(resolvableType, AggregatePersistence.class, 0);
                if (aggretateClass != null) {
                    registerAggregatePersistence(aggretateClass.getName(), beanDefinitionName);
                }
                continue;

            }
            if (beanDefinition instanceof AnnotatedBeanDefinition) {
                final MethodMetadata factoryMethodMetadata = ((AnnotatedBeanDefinition) beanDefinition).getFactoryMethodMetadata();
                if (factoryMethodMetadata != null) {
                    // 找AggregateRootLoader 的敢兴趣的类
                    final String returnTypeName = factoryMethodMetadata.getReturnTypeName();
                    if (AggregateRootLoader.class.getName().equals(returnTypeName)) {
                        final Class<Object> declaringClass = ClassUtil.loadClass(factoryMethodMetadata.getDeclaringClassName());
                        // 因为现在获取不到参数，所以只能通过变量来获取
                        final Method[] methods = ReflectUtil.getPublicMethods(declaringClass);
                        final Optional<Method> matchedMethod = Arrays.stream(methods).filter(m -> m.getName().equals(factoryMethodMetadata.getMethodName())).findAny();
                        if (matchedMethod.isPresent()) {
                            final ResolvableType resolvableType = ResolvableType.forMethodReturnType(matchedMethod.get());
                            final ResolvableType[] generics = resolvableType.getGenerics();
                            if (generics.length > 0) {

                                String businessIdName = Objects.requireNonNull(generics[0].getRawClass()).getName();
                                String aggregateRootName = Objects.requireNonNull(generics[1].getRawClass()).getName();
                                // 这时候还不能提前获取bean
                                registerAggregateRootLoader(businessIdName, aggregateRootName, beanDefinitionName);
                            }

                        }
                    }

                    if (AggregatePersistence.class.getName().equals(returnTypeName)) {
                        final Class<Object> declaringClass = ClassUtil.loadClass(factoryMethodMetadata.getDeclaringClassName());
                        // 因为现在获取不到参数，所以只能通过变量来获取
                        final Method[] methods = ReflectUtil.getPublicMethods(declaringClass);
                        final Optional<Method> matchedMethod = Arrays.stream(methods).filter(m -> m.getName().equals(factoryMethodMetadata.getMethodName())).findAny();
                        if (matchedMethod.isPresent()) {
                            final ResolvableType resolvableType = ResolvableType.forMethodReturnType(matchedMethod.get());
                            final ResolvableType[] generics = resolvableType.getGenerics();
                            if (generics.length > 0) {
                                String businessName = Objects.requireNonNull(generics[0].getRawClass()).getName();
                                // 这时候还不能提前获取bean
                                registerAggregatePersistence(businessName, beanDefinitionName);
                            }

                        }
                    }
                }


            }

        }


    }

    private Class<?> getResolvableType(ResolvableType resolvableType, Class<?> type, int index) {
        if (resolvableType == null || ResolvableType.NONE == resolvableType) {
            return null;
        }
        if (type.equals(resolvableType.getRawClass())) {
            final ResolvableType[] generics = resolvableType.getGenerics();
            if (generics.length > index) {
                return generics[index].resolve();
            }
        }
        // 接口类型
        for (ResolvableType anInterface : resolvableType.getInterfaces()) {
            // 接口上定义接口
            for (ResolvableType superResType : anInterface.getInterfaces()) {
                Class<?> result = getResolvableType(superResType, type, index);
                if (result != null) {
                    return result;
                }
            }
            //
            Class<?> result = getResolvableType(anInterface, type, index);
            if (result != null) {
                return result;
            }
        }
        // 父类
        return getResolvableType(resolvableType.getSuperType(), type, index);
    }

    @Override
    public void afterSingletonsInstantiated() {
        final SpringExecutionContext springExecutionContext = beanFactory.getBean(SpringExecutionContext.class);
       /* for (Map.Entry<String, String> entry : this.aggregateRootLoaderMap.entrySet()) {
            springExecutionContext.registerAggregateRootLoader(entry.getKey(), (AggregateRootLoader) beanFactory.getBean(entry.getValue()));
        }
        for (Map.Entry<String, String> entry : this.aggregatePersistenceMap.entrySet()) {
            springExecutionContext.registerAggregatePersistence(entry.getKey(), (AggregatePersistence) beanFactory.getBean(entry.getValue()));
        }*/
        //springExecutionContext.addExecuteInterceptor(PersistenceExecutor.NAME, beanFactory.getBean(TxExecuteInterceptor.class));
    }
}